import { expect } from 'chai';
import * as sinon from 'sinon';
import * as path from 'path';
import * as step from '@flow-step/step-toolkit';
import * as paramsModule from '../src/params';

// 创建一个简单的测试版本的getTemplateBody函数
function createTestableGetTemplateBody(mockFs: any) {
  return function getTemplateBody(): any {
    const params = paramsModule.getParams();
    const stackFilePath = params.ROS_STACK_FILE_PATH;
    const projectDir: string = params.projectDir;
    let templateFilePath = path.join(projectDir + '/' + stackFilePath);
    
    const ext = templateFilePath.split('.').pop()?.toLowerCase() ?? '';
    if (!['json', 'yaml', 'yml'].includes(ext)) {
      step.error(`Invalid template file extension. File: ${params.ROS_STACK_FILE_PATH} Supported: json, yaml, yml`);
      process.exit(-1);
    } else {
      let templateFileContent = mockFs.readFileSync(templateFilePath).toString();
      return templateFileContent;
    }
  };
}

describe('getTemplateBody', () => {
    let sandbox: sinon.SinonSandbox;
    let getParamsStub: sinon.SinonStub;
    let mockFs: any;
    let stepErrorStub: sinon.SinonStub;
    let processExitStub: sinon.SinonStub;

    beforeEach(() => {
      sandbox = sinon.createSandbox();
      getParamsStub = sandbox.stub(paramsModule, 'getParams');
      stepErrorStub = sandbox.stub(step, 'error');
      processExitStub = sandbox.stub(process, 'exit');
      
      mockFs = {
        readFileSync: sandbox.stub().returns(Buffer.from(''))
      };
    });

    afterEach(() => {
      sandbox.restore();
    });

  it('should read template file content successfully', () => {
      const mockParams = {
        ROS_STACK_FILE_PATH: 'template.json',
        projectDir: '/test/project',
        STACK_NAME: 'test-stack',
        REGION_ID: 'cn-hangzhou',
        pipelineID: 123,
        pipelineName: 'test-pipeline',
        workSpace: '/test/workspace',
        buildJobID: 456,
        ROS_DEPLOYMENT_LOCATION: 'cn',
        RAM_ROLE_NAME: 'test-role',
        TIMEOUT_MINUTES: 60
      };
      const templateContent = '{"Resources": {"Test": {"Type": "ALIYUN::ECS::Instance"}}}';

      getParamsStub.returns(mockParams);
      mockFs.readFileSync.returns(Buffer.from(templateContent));

      const getTemplateBody = createTestableGetTemplateBody(mockFs);
      const result = getTemplateBody();

      expect(result).to.equal(templateContent);
      expect(mockFs.readFileSync.calledWith('/test/project/template.json')).to.be.true;
    });

  it('should support .json extension', () => {
      const mockParams = {
        ROS_STACK_FILE_PATH: 'stack.json',
        projectDir: '/test'
      };
      const templateContent = '{"test": "json"}';

      getParamsStub.returns(mockParams);
      mockFs.readFileSync.returns(Buffer.from(templateContent));

      const getTemplateBody = createTestableGetTemplateBody(mockFs);
      const result = getTemplateBody();

      expect(result).to.equal(templateContent);
      expect(stepErrorStub.called).to.be.false;
      expect(processExitStub.called).to.be.false;
    });

  it('should support .yaml extension', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'stack.yaml',
      projectDir: '/test'
    };
    const templateContent = 'test: yaml';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
  });

  it('should support .yml extension', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'stack.yml',
      projectDir: '/test'
    };
    const templateContent = 'test: yml';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
  });

  it('should handle uppercase extensions', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'stack.JSON',
      projectDir: '/test'
    };
    const templateContent = '{"test": "uppercase"}';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
    expect(stepErrorStub.called).to.be.false;
  });

  it('should exit with error for invalid file extension', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'template.txt',
      projectDir: '/test/project'
    };

    getParamsStub.returns(mockParams);

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    getTemplateBody();

    expect(stepErrorStub.calledWith('Invalid template file extension. File: template.txt Supported: json, yaml, yml')).to.be.true;
    expect(processExitStub.calledWith(-1)).to.be.true;
  });

  it('should exit with error for file without extension', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'template',
      projectDir: '/test/project'
    };

    getParamsStub.returns(mockParams);

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    getTemplateBody();

    expect(stepErrorStub.calledWith('Invalid template file extension. File: template Supported: json, yaml, yml')).to.be.true;
    expect(processExitStub.calledWith(-1)).to.be.true;
  });

  it('should handle complex file paths', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'path/to/nested/stack.json',
      projectDir: '/complex/project'
    };
    const templateContent = '{"complex": "path"}';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
    expect(mockFs.readFileSync.calledWith('/complex/project/path/to/nested/stack.json')).to.be.true;
  });

  it('should handle absolute paths in projectDir', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'template.yaml',
      projectDir: '/absolute/path'
    };
    const templateContent = 'absolute: path';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
    expect(mockFs.readFileSync.calledWith('/absolute/path/template.yaml')).to.be.true;
  });

  it('should handle special characters in file content', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'template.json',
      projectDir: '/test'
    };
    const templateContent = '{"special": "!@#$%^&*()_+"}';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
  });

  it('should handle large template files', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'large-template.json',
      projectDir: '/test'
    };
    const largeContent = '{"Resources": {' + Array(1000).fill('"Test": {"Type": "ALIYUN::ECS::Instance"}').join(',') + '}}';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(largeContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(largeContent);
  });

  it('should handle file read errors', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'nonexistent.json',
      projectDir: '/test'
    };

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.throws(new Error('ENOENT: no such file or directory'));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    expect(() => getTemplateBody()).to.throw('ENOENT: no such file or directory');
  });

  it('should handle empty file extension', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'template.',
      projectDir: '/test'
    };

    getParamsStub.returns(mockParams);

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    getTemplateBody();

    expect(stepErrorStub.calledWith('Invalid template file extension. File: template. Supported: json, yaml, yml')).to.be.true;
    expect(processExitStub.calledWith(-1)).to.be.true;
  });

  it('should handle mixed case extensions', () => {
    const mockParams = {
      ROS_STACK_FILE_PATH: 'stack.YaMl',
      projectDir: '/test'
    };
    const templateContent = 'test: mixed case';

    getParamsStub.returns(mockParams);
    mockFs.readFileSync.returns(Buffer.from(templateContent));

    const getTemplateBody = createTestableGetTemplateBody(mockFs);
    const result = getTemplateBody();

    expect(result).to.equal(templateContent);
    expect(mockFs.readFileSync.calledWith('/test/stack.YaMl')).to.be.true;
  });

  it('should handle relative projectDir', () => {
      const mockParams = {
        ROS_STACK_FILE_PATH: 'template.json',
        projectDir: './relative'
      };
      const templateContent = '{"relative": "path"}';

      getParamsStub.returns(mockParams);
      mockFs.readFileSync.returns(Buffer.from(templateContent));

      const getTemplateBody = createTestableGetTemplateBody(mockFs);
      const result = getTemplateBody();

      expect(result).to.equal(templateContent);
      expect(mockFs.readFileSync.calledWith('relative/template.json')).to.be.true;
    });
});